/*
 * TcpServer.cpp
 *
 *   Created on: 2010-1-23     
 *  Description: 
 *    Copyright: 2010 @ ICT Li Heyuan
 */

#include "../../include/server/TcpServer.h"
#include "../../include/util/Util.h"
#include "../../include/method/RpcMethod.h"

#include <sys/epoll.h>

#include <iostream>
#include <string>
#include <map>
#include <list>
using std::cerr;
using std::cout;
using std::endl;
using std::string;
using std::map;
using std::list;

#define MAX_EVENTS 128	//最大的epoll事件个数
TcpServer::TcpServer(unsigned int port, int backlog/* = 20*/,
		const std::string ip /* ="" */) :
	Server(port, backlog, ip)
{
}

TcpServer::~TcpServer()
{
	//清空TcpServerConn
	for (ConnMap::iterator itr = _connMap.begin(); itr != _connMap.end(); itr++)
	{
		if (itr->second)
		{
			delete itr->second;
		}
	}
	_connMap.clear();

	//清空RpcMethod
	for (MethodMap::iterator itr = _methodMap.begin(); itr != _methodMap.end(); itr++)
	{
		if (itr->second)
		{
			delete itr->second;
		}
	}
	_methodMap.clear();

	_log_server.info("json-rpc-server destory");
}

bool TcpServer::init()
{
	//获得listenFd
	_listenFd = Network::socket();
	Network::setReuseAddr(_listenFd);

	if (_listenFd == -1)
	{
		_log_server.error("listen sockFd create fail : %s",
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}

	//绑定端口
	if (!Network::bind(_listenFd, _addr.port, _addr.ip))
	{
		_log_server.error("bind to port %d fail : %s", _addr.port,
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}

	//监听
	if (!Network::listen(_listenFd, _backlog))
	{
		_log_server.error("listen sockFd %d fail : %s", _listenFd,
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}

	_log_server.info("success bind/listen on port %d", _addr.port);
	return true;
}

void TcpServer::service()
{

	//使用epoll模型
	struct epoll_event ev, events[MAX_EVENTS];
	int nfds;

	//创建epollfd,size任意
	_epollfd = epoll_create(MAX_EVENTS / 2);
	if (_epollfd == -1)
	{
		//epoll创建失败
		_log_server.error("epoll_event create fail : %s",
				Util::getInstance()->getErrMsg().c_str());
		return;
	}

	//把serverfd加入
	ev.events = EPOLLIN;
	ev.data.fd = _listenFd;
	if (epoll_ctl(_epollfd, EPOLL_CTL_ADD, _listenFd, &ev) == -1)
	{
		//serverfd加入失败
		_log_server.error("add listenFd to epoll_event fail : %s",
				Util::getInstance()->getErrMsg().c_str());
		return;
	}

	_log_server.info("success init epoll_event");

	for (;;)
	{
		//等待事件发生
		nfds = epoll_wait(_epollfd, events, MAX_EVENTS, -1);
		if (nfds == -1)
		{
			//epoll出错
			_log_server.error("epoll_wait fail : %s",
					Util::getInstance()->getErrMsg().c_str());
			continue;
		}

		//处理每一个epoll事件
		for (int i = 0; i < nfds; i++)
		{

			if (events[i].data.fd == -1)
			{
				//-1为无效的fd，跳过
				continue;
			}

			if (events[i].data.fd == _listenFd)
			{
				//新的连接
				int connfd;
				EasyAddr addr;
				connfd = Network::accept(_listenFd, addr);
				if (connfd == -1)
				{
					_log_server.error("accept %s:%d fail : %s",
							addr.ip.c_str(), addr.port,
							Util::getInstance()->getErrMsg().c_str());
				}
				Network::setNonBlocking(connfd);//设置为非阻塞
				Network::setLinger(connfd);//close后一直发送数据到完毕

				//加入epoll监视读、写，边缘模式
				ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
				ev.data.fd = connfd;
				if (epoll_ctl(_epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1)
				{
					_log_server.error("add clientFd to epoll fail : %s",
							Util::getInstance()->getErrMsg().c_str());
				}

				//connMap中加入(fd,TcpServerConn)
				addConn(connfd, addr);

				_log_server.info("new client fd=%d %s:%d", connfd,
						addr.ip.c_str(), addr.port);

			}//end if 有新连接
			else
			{
				//不是新连接，则交给已经有的处理
				bool isContinue = true;
				if (events[i].events & EPOLLIN)
				{
					//ready for read
					isContinue = event_in(events[i], _epollfd);
					//					cout << "EPOLLIN handle() 返回" << isContinue << endl;
				}
				if (isContinue && events[i].events & EPOLLOUT)
				{
					//ready for write
					isContinue = event_out(events[i], _epollfd);
				}

				if (!isContinue)
				{
					//不继续监控了
					int fd = events[i].data.fd;
					removeConn(fd, true);
				}//end if不需要继续监控

			}//end if 非新连接
		}//end for 每个epoll事件

		//尚未安全删除
		delSafeConn();

		//清理超时连接
		removeTimeoutConn();
	}//for(;;)
}

Conn* TcpServer::newConn(int sock, const EasyAddr &addr)
{
	return new TcpConn(this, sock, addr);
}

bool TcpServer::event_in(struct epoll_event &ev, int epoll)
{

	//先定位fd关联的conn
	int fd = ev.data.fd;
	ConnMap::iterator itr = _connMap.find(fd);
	if (itr != _connMap.end())
	{
		Conn * conn = itr->second;
		if (conn->handle(EPOLL_IN))
		{
			//继续监控
			return true;
		}
	}
	//没有找到epoll_event关联的fd,或者handle说不需要监控了，返回false
	return false;

}

bool TcpServer::event_out(struct epoll_event &ev, int epoll)
{

	//先定位fd关联的conn
	int fd = ev.data.fd;
	ConnMapItr itr = _connMap.find(fd);
	if (itr != _connMap.end())
	{
		Conn * conn = itr->second;
		if (conn->handle(EPOLL_OUT))
		{
			//继续监控
			return true;
		}
	}
	//没有找到监控的,或者handle说不需要监控了，返回false
	return false;
}

void TcpServer::addConn(int sock, const EasyAddr &addr)
{
	//如果已经有Conn，先删除，但是不关闭sock(因为重生了!)
	removeConn(sock, false);
	_connMap[sock] = newConn(sock, addr);
}

void TcpServer::removeConn(int sock, bool close)
{
	//先查找
	ConnMapItr itr = _connMap.find(sock);
	if (itr != _connMap.end())
	{
		//找到，删除之，并删除在epoll中的监控
		if (close)
		{
			itr->second->close();
		}
		if (itr->second)
		{
			if (itr->second->isSafeDel())
			{
				//可以安全删除
				delete itr->second;
			}
			else
			{
				//转入另外的队列
				_laterDel.push_back(itr->second);
			}
		}
		_connMap.erase(itr);

		if (close)
		{
			struct epoll_event evt; //为了2.6.9的Bug
			epoll_ctl(_epollfd, EPOLL_CTL_DEL, sock, &evt);
		}

		//记录日志
		if (!close)
		{
			_log_server.info("client fd=%d old free memory", sock, close);
		}
		else
		{
			_log_server .info("bye client fd=%d", sock);
		}
	}
}

void TcpServer::removeTimeoutConn()
{
	//检查是否设置了连接时间限制
	if (!_max_conn_work_time)
	{
		return;
	}

	//当前时间
	time_t now = time(NULL);
	list<int> removed;

	//找多所有超时连接
	ConnMapItr itr = _connMap.begin();
	while (itr != _connMap.end())
	{
		if ((now - itr->second->getStartTime() > _max_conn_work_time))
		{
			removed.push_back(itr->first);
		}
		itr++;
	}

	//删除所有超时的
	list<int>::iterator itr2 = removed.begin();
	while (itr2 != removed.end())
	{
		_log_server.info("exceed max work time fd=%d", *itr2);
		removeConn(*itr2);
		itr2++;
	}
}

void TcpServer::delSafeConn()
{
	if (_laterDel.empty())
	{
		return;
	}

	ConnListItr itr = _laterDel.begin();
	while (itr != _laterDel.end())
	{
		if ((*itr)->isSafeDel())
		{
			//			cout << _laterDel.size() << endl;
			delete (*itr);
			itr = _laterDel.erase(itr);
			//			cout << "later del" << endl;
			//			cout << _laterDel.size() << endl;
		}
		else
		{
			itr++;
		}
	}
}
